#include "vsf.h"
#include "vsfjeg.h"

#include <SDL/SDL.h>

SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
uint32_t pixels[256 * 240];

static const uint32_t rgb_palette[64] = {
	0x7C7C7C, 0x0000FC, 0x0000BC, 0x4428BC, 0x940084, 0xA80020, 0xA81000, 0x881400,
	0x503000, 0x007800, 0x006800, 0x005800, 0x004058, 0x000000, 0x000000, 0x000000,
	0xBCBCBC, 0x0078F8, 0x0058F8, 0x6844FC, 0xD800CC, 0xE40058, 0xF83800, 0xE45C10,
	0xAC7C00, 0x00B800, 0x00A800, 0x00A844, 0x008888, 0x000000, 0x000000, 0x000000,
	0xF8F8F8, 0x3CBCFC, 0x6888FC, 0x9878F8, 0xF878F8, 0xF85898, 0xF87858, 0xFCA044,
	0xF8B800, 0xB8F818, 0x58D854, 0x58F898, 0x00E8D8, 0x787878, 0x000000, 0x000000,
	0xFCFCFC, 0xA4E4FC, 0xB8B8F8, 0xD8B8F8, 0xF8B8F8, 0xF8A4C0, 0xF0D0B0, 0xFCE0A8,
	0xF8D878, 0xD8F878, 0xB8F8B8, 0xB8F8D8, 0x00FCFC, 0xF8D8F8, 0x000000, 0x000000
};

#define VSFJEG_DECODER_EVT_SYNC				(VSFSM_EVT_USER + 0)
#define VSFJEG_DECODER_EVT_OUT				(VSFSM_EVT_USER + 1)

static void vsfjeg_decoder_on_sync(struct vsfav_adapter_t *adapter)
{
	struct vsfjeg_decoder_t *decoder = (struct vsfjeg_decoder_t *)adapter;
	vsfsm_post_evt_pending(&decoder->sm, VSFJEG_DECODER_EVT_SYNC);
}

void vsfjeg_decoder_on_inout(struct vsfav_adapter_t *adapter, bool isin)
{
	struct vsfjeg_decoder_t *decoder = (struct vsfjeg_decoder_t *)adapter;
	if (!isin && decoder->out_pend)
	{
		decoder->out_pend = false;
		vsfsm_post_evt_pending(&decoder->sm, VSFJEG_DECODER_EVT_OUT);
	}
}

static void vsfjeg_decoder_update_frame(uint8_t *frame_data)
{
	for (uint32_t i = 0; i<256 * 240; i++)
		pixels[i] = rgb_palette[frame_data[i]];

	SDL_UpdateTexture(texture, NULL, pixels, 256 * sizeof(uint32_t));
	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, texture, NULL, NULL);
	SDL_RenderPresent(renderer);
}

static struct vsfsm_state_t *
vsfjeg_decoder_evthandler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
	struct vsfjeg_decoder_t *decoder = (struct vsfjeg_decoder_t *)sm->user_data;
	struct vsf_buffer_t rxbuf;

	switch (evt)
	{
	case VSFSM_EVT_INIT:
		decoder->out_pend = false;
		decoder->sync = 0;
		decoder->buflist[0] = decoder->buffer[0];
		decoder->buflist[1] = decoder->buffer[1];
		decoder->mbuf.mem.multibuf.size = sizeof(decoder->buffer[0]);
		decoder->mbuf.mem.multibuf.buffer_list = decoder->buflist;
		decoder->mbuf.mem.multibuf.count = dimof(decoder->buflist);
		decoder->mbuf.stream.op = &vsf_mbufstream_op;
		VSFSTREAM_INIT(&decoder->mbuf);
		VSFSTREAM_CONNECT_TX(&decoder->mbuf);
		decoder->outstream.stream = &decoder->mbuf.stream;
		decoder->adapter.out = &decoder->outstream;
		vsfav_adapter_init(&decoder->adapter, vsfjeg_decoder_on_inout,
			vsfjeg_decoder_on_sync);
		break;
	case VSFJEG_DECODER_EVT_SYNC:
		decoder->sync++;
		if (decoder->sync > 1)
			break;

		while (decoder->sync)
		{
			decoder->size = VSFSTREAM_GET_RBUF(decoder->adapter.in->stream,
					&decoder->ptr);
			while (decoder->size > 0)
			{
				rxbuf.buffer = decoder->ptr;
				rxbuf.size = decoder->size;

				vsfjeg_decoder_update_frame(rxbuf.buffer);

				decoder->size -= rxbuf.size;
			}
			VSFSTREAM_READ(decoder->adapter.in->stream, NULL);
			vsfsm_sem_post(&decoder->outstream.frame_sync);
			decoder->sync--;
		}
		break;
	}
	return NULL;
}

vsf_err_t vsfjeg_decoder_init(struct vsfjeg_decoder_t *decoder,
		struct vsfav_stream_t *stream)
{
	int ret = SDL_Init(SDL_INIT_VIDEO);
	if (ret < 0) {
		vsfdbg_printf("SDL_Init failed %d" VSFCFG_DEBUG_LINEEND, ret);
		return VSFERR_FAIL;
	}
	window = SDL_CreateWindow("JEG", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 256 * 2, 240 * 2, 0);
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
	SDL_RenderSetLogicalSize(renderer, 256, 240);
	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 256, 240);

	decoder->adapter.in = stream;
	decoder->sm.init_state.evt_handler = vsfjeg_decoder_evthandler;
	decoder->sm.user_data = decoder;
	return vsfsm_init(&decoder->sm);
}
